﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

namespace vBridge.Dwm.Aero.Margins
{
    /// <summary>Represents a margins structure.</summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct Margin : IMargins, IEquatable<Margin>
    {
        #region Fields

        public Int32 Left { get; set; }
        public Int32 Right { get; set; }
        public Int32 Top { get; set; }
        public Int32 Bottom { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="Margin" /> class.
        /// </summary>
        /// <param name="margins">Source margins for deep-clone.</param>
        public Margin(IMargins margins)
            : this()
        {
            if (margins == null)
                throw new ArgumentNullException("margins");
            Left = margins.Left;
            Top = margins.Top;
            Right = margins.Right;
            Bottom = margins.Bottom;
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="Margin" /> class.
        /// </summary>
        /// <param name="left">Left margin value.</param>
        /// <param name="top">Top margin value.</param>
        /// <param name="right">Right margin value.</param>
        /// <param name="bottom">Bottom margin value.</param>
        public Margin(Int32 left, Int32 top, Int32 right, Int32 bottom)
            : this()
        {
            Left = left;
            Top = top;
            Right = right;
            Bottom = bottom;
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="Margin" /> class.
        /// </summary>
        /// <param name="horizontalMargins">Left and right margins value.</param>
        /// <param name="verticalMargins">Top and bottom margins value.</param>
        public Margin(Int32 horizontalMargins, Int32 verticalMargins)
            : this(horizontalMargins, verticalMargins, horizontalMargins, verticalMargins)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="Margin" /> class.
        /// </summary>
        /// <param name="margins">Margin value for all of the sides (left, top, right, and bottom).</param>
        public Margin(Int32 margins)
            : this(margins, margins)
        {
        }

        #endregion

        #region Equality Methods

        public Boolean Equals(Margin other)
        {
            return
                Left == other.Left &&
                Top == other.Top &&
                Right == other.Right &&
                Bottom == other.Bottom;
        }

        public override Boolean Equals(Object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is Margin && Equals((Margin) obj);
        }

        public override Int32 GetHashCode()
        {
            unchecked
            {
                int hashCode = Left;
                hashCode = (hashCode*397) ^ Top;
                hashCode = (hashCode*397) ^ Right;
                hashCode = (hashCode*397) ^ Bottom;
                return hashCode;
            }
        }

        public static Boolean operator ==(Margin left, Margin right)
        {
            return left.Equals(right);
        }

        public static Boolean operator !=(Margin left, Margin right)
        {
            return !left.Equals(right);
        }

        #endregion

        [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider",
            MessageId = "System.String.Format(System.String,System.Object[])")]
        public override String ToString()
        {
            return String.Format("{{{0},{1},{2},{3}}}", Left, Top, Right, Bottom);
        }
    }
}